#ifndef __MATRIX_H__
#define __MATRIX_H__

#include <iostream>

class Matrix
{
public:
    Matrix()
        : _matrix(new char[64])
    {
        reset();
    }
    Matrix(const char *data)
        : _matrix(new char[64])
    {
        set(data);
    }
    Matrix(const Matrix &rhs)
        : _matrix(new char[64])
    {
        memcpy(this->_matrix, rhs._matrix, 64);
    }
    Matrix(Matrix &&rhs)
        : _matrix(rhs._matrix)
    {
        rhs._matrix = nullptr;
    }
    const Matrix &operator = (const Matrix &rhs)
    {
        memcpy(this->_matrix, rhs._matrix, 64);
        return *this;
    }
    const Matrix &operator = (Matrix &&rhs)
    {
        if (this != &rhs)
        {
            this->_matrix = rhs._matrix;
            rhs._matrix = nullptr;
        }
        return *this;
    }
    ~Matrix()
    {
        delete _matrix;
        _matrix = nullptr;
    }
public:
    void reset()
    {
        for (int i = 0; i < 64; i++)
        {
            _matrix[i] = 64 - 1 - i;
        }
    }
    void set(const char *data)
    {
        memmove(_matrix, data, 64);
    }
    const char *constMatrix() const
    {
        return _matrix;
    }
public:
    void swapBits(char) = delete;
    void swapBits(char *swapMaskBytes)
    {
        for (int i = 0; i < 32; i++)
        {
            if (swapMaskBytes[i])
            {
                using namespace std;
                swap(_matrix[i], _matrix[i + 32]);
            }
        }
    }
    void swapBits(unsigned int swapMask)
    {
        char swapMaskBytes[32];
        bitsMask2bytesMask(swapMaskBytes, swapMask);
        return swapBits(swapMaskBytes);
    }

    static void bitsMask2bytesMask(char * swapMaskBytes, unsigned int swapMask)
    {
        for (int i = 0; i < 32; i++)
        {
            swapMaskBytes[i] = (swapMask >> (31 - i)) & 1;
        }
    }

    void rolLeft(int n)
    {
        return rol(_matrix, n);
    }
    void rorLeft(int n)
    {
        return ror(_matrix, n);
    }
    void rolRight(int n)
    {
        return rol(_matrix + 32, n);
    }
    void rorRight(int n)
    {
        return ror(_matrix + 32, n);
    }
private:

    template <class T, int size = 32>
    void rol(T *head, int n)
    {
        char temp[size];

        // save head
        memcpy(temp, head, n);

        // copy right part to head
        memmove(head, head + n, size - n);

        // restore original head to tail
        memcpy(head + size - n, temp, n);
    }
    template <class T, int size = 32>
    void ror(T *head, int n)
    {
        char temp[size];

        // save tail
        memcpy(temp, head + size - n, n);

        // move head to offset n
        memmove(head + n, head, size - n);

        // restore original tail to head
        memcpy(head, temp, n);
    }
public:
    void printIntMatrix()
    {
        for (int i = 0; i < 32; i++)
        {
            printf("%-4d", _matrix[i]);
            if (i % 8 == 7)
                putchar('\n');
        }
        printf("%s\n", "--------------------------------");
        for (int i = 32; i < 64; i++)
        {
            printf("%-4d", _matrix[i]);
            if (i % 8 == 7)
                putchar('\n');
        }
    }
public:
    bool compare(const Matrix &rhs) const
    {
        return memcmp(this->constMatrix(), rhs.constMatrix(), 64) == 0;
    }
    bool operator == (const Matrix &rhs) const
    {
        return compare(rhs);
    }
    bool operator != (const Matrix &rhs) const
    {
        return !compare(rhs);
    }
private:
    char *_matrix; // big-endian
};


#endif // __MATRIX_H__